package com.webex.ta.hydra.gui.autocomplete;

import sun.swing.UIAction;

import javax.swing.*;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

/**
 * Created by Cisco WebEx.
 * User: vegaz
 * Date: 2010-8-16
 * Time: 14:31:50
 */
public class AutoCompleteComboBoxUI extends MetalComboBoxUI {

    private boolean updatingPopupList = false;

    public AutoCompleteComboBoxUI() {
        super();
    }

    @Override
    public void installUI(JComponent c) {
        if (!(c instanceof AutoCompleteComboBox))
            throw new IllegalArgumentException("AutoCompleteComboBoxUI can only be applied to AutoCompleteComboBox");
        super.installUI(c);
        ActionMap actionMap = c.getActionMap();
        Action enterAction = new UIAction("enterPressed") {
            public void actionPerformed(ActionEvent e) {
                if (comboBox.isPopupVisible()) {
                    // Forces the selection of the list item
                    boolean isEnterSelectablePopup =
                            UIManager.getBoolean("ComboBox.isEnterSelectablePopup");
                    if (!comboBox.isEditable() || isEnterSelectablePopup) {
                        Object listItem = popup.getList().getSelectedValue();
                        if (listItem != null) {
                            comboBox.getModel().setSelectedItem(listItem);
                            // Ensure that JComboBox.actionPerformed()
                            // doesn't set editor value as selected item
                            comboBox.getEditor().setItem(listItem);
                        }
                    }
                    comboBox.setPopupVisible(false);
                }
                else {
                    // Call the default button binding.
                    // This is a pretty messy way of passing an event through
                    // to the root pane.
                    JRootPane root = SwingUtilities.getRootPane(comboBox);
                    if (root != null) {
                        InputMap im = root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
                        ActionMap am = root.getActionMap();
                        if (im != null && am != null) {
                            Object obj = im.get(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0));
                            if (obj != null) {
                                Action action = am.get(obj);
                                if (action != null) {
                                    action.actionPerformed(new ActionEvent(
                                     root, e.getID(), e.getActionCommand(),
                                     e.getWhen(), e.getModifiers()));
                                }
                            }
                        }
                    }
                }
            }
        };
        actionMap.put("enterPressed", enterAction);
    }

    protected ComboPopup createPopup() {
        return new AutoCompleteComboPopup((AutoCompleteComboBox) comboBox);
    }

    public void updatePopupList(Object[] items) {
        updatingPopupList = true;
        MutableComboBoxModel model = (MutableComboBoxModel) listBox.getModel();
        if (model.getSize() > 0) {
            for (int i = model.getSize() - 1; i >= 0; i--) {
                try {
                    model.removeElementAt(i);
                } catch (ArrayIndexOutOfBoundsException e) {
                }
            }
        }

        for (Object item : items) {
            model.addElement(item);
        }
        updatingPopupList = false;
    }

//    protected void selectNextPossibleValue() {
//        int si = listBox.getSelectedIndex();
////        System.out.println("selectNextPossibleValue:" + si + "," + (listBox.getModel().getSize() - 1));
//        if (si < listBox.getModel().getSize() - 1) {
//            listBox.setSelectedIndex(si + 1);
//            listBox.ensureIndexIsVisible(si + 1);
////            comboBox.setSelectedIndex(si+1);
//            comboBox.setSelectedItem(listBox.getModel().getElementAt(si + 1));
//            comboBox.repaint();
//        }
//    }

//    protected void selectPreviousPossibleValue() {
//        int si = listBox.getSelectedIndex();
////        System.out.println("selectPreviousPossibleValue:" + si);
//        if (si > 0) {
//            listBox.setSelectedIndex(si - 1);
//            listBox.ensureIndexIsVisible(si - 1);
////            comboBox.setSelectedIndex(si-1);
//            comboBox.setSelectedItem(listBox.getModel().getElementAt(si - 1));
//            comboBox.repaint();
////            propertyChangeListener.propertyChange();
//        }
//    }

//    protected Dimension getDisplaySize() {
//
//        Dimension result = new Dimension();
//
//        ListCellRenderer renderer = comboBox.getRenderer();
//        if (renderer == null) {
//            renderer = new DefaultListCellRenderer();
//        }
//
//        boolean sameBaseline = true;
//
////        Object prototypeValue = comboBox.getPrototypeDisplayValue();
////        if (prototypeValue != null) {
////            // Calculates the dimension based on the prototype value
////            result = getSizeForComponent(renderer.getListCellRendererComponent(listBox,
////                    prototypeValue,
////                    -1, false, false));
////        } else {
//            // Calculate the dimension by iterating over all the elements in the combo
//            // box list.
//            ComboBoxModel model = comboBox.getModel();
//            int modelSize = model.getSize();
//            int baseline = -1;
//            Dimension d;
//
//            Component cpn;
//
//            if (modelSize > 0) {
//                for (int i = 0; i < modelSize; i++) {
//                    // Calculates the maximum height and width based on the largest
//                    // element
//                    Object value = model.getElementAt(i);
//                    Component c = renderer.getListCellRendererComponent(
//                            listBox, value, -1, false, false);
//                    d = getSizeForComponent(c);
//                    if (sameBaseline && value != null &&
//                            (!(value instanceof String) || !"".equals(value))) {
//                        int newBaseline = c.getBaseline(d.width, d.height);
//                        if (newBaseline == -1) {
//                            sameBaseline = false;
//                        } else if (baseline == -1) {
//                            baseline = newBaseline;
//                        } else if (baseline != newBaseline) {
//                            sameBaseline = false;
//                        }
//                    }
//                    result.width = Math.max(result.width, d.width);
//                    result.height = Math.max(result.height, d.height);
//                }
//            } else {
//                result = getDefaultSize();
//                if (comboBox.isEditable()) {
//                    result.width = 100;
//                }
//            }
////        }
//
//        if (comboBox.isEditable()) {
//            Dimension d1 = editor.getPreferredSize();
//            result.width = Math.max(result.width, d1.width);
//            result.height = Math.max(result.height, d1.height);
//        }
//
//        return result;
//    }
//
//    private Dimension getSizeForComponent(Component comp) {
//        currentValuePane.add(comp);
//        comp.setFont(comboBox.getFont());
//        Dimension d = comp.getPreferredSize();
//        currentValuePane.remove(comp);
//        return d;
//    }


    protected ListDataListener createListDataListener() {
        return new ListDataListener() {

            public void intervalAdded(ListDataEvent e) {
                contentsChanged(e);
            }

            public void intervalRemoved(ListDataEvent e) {
                contentsChanged(e);
            }

            public void contentsChanged(ListDataEvent e) {
//                if (!(e.getIndex0() == -1 && e.getIndex1() == -1)) {
                    isMinimumSizeDirty = true;
                    comboBox.revalidate();
//                }

                // set the editor with the selected item since this
                // is the event handler for a selected item change.
                if (comboBox.isEditable() && editor != null && !updatingPopupList) {
                    comboBox.configureEditor(comboBox.getEditor(),
                            comboBox.getSelectedItem());
                }


                comboBox.repaint();
                if (popup.isVisible()) {
                    popup.hide();
                    popup.show();
                }
            }
        };
    }
}
